import constValue from './const'
import config from './config'
import { clockFactory } from './func'

export const dayArr = ['日', '一', '二', '三', '四', '五', '六']

/**
 * 日期信息的操作类
 */
class DateClass {
  getWeek(week: number) {
    return `周${dayArr[week]}`
  }

  getCurrent() {
    const date = new Date()
    return [date.getFullYear(), date.getMonth() + 1, date.getDate()]
  }

  changeTimeStr(time: string) {
    return time.split('-').map(el => Number(el))
  }

  getCurrentStr(isZero: boolean = false) {
    const date = new Date()
    return isZero
      ? `${date.getFullYear()
          }-${
          clockFactory(date.getMonth() + 1)
          }-${
          clockFactory(date.getDate())}`
      : `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
  }

  /** 判断是否休息 */
  getHolidays(date: number[], time: string[] = []) {
    return [...config.Holidays, ...time].includes(
      `${date[0]}${clockFactory(date[1]!)}${clockFactory(date[2]!)}`,
    )
  }

  /** 判断是否加班 */
  getWorks(date: number[], time: string[] = []) {
    return [...config.Works, ...time].includes(
      `${date[0]}${clockFactory(date[1]!)}${clockFactory(date[2]!)}`,
    )
  }

  /**
   * 获取公历月份天数
   * @param {number} y 年
   * @param {number} m 月
   * @returns {number} 返回输入月份天数
   */
  solarMonth(y: number, m: number) {
    if (m == 2)
      return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 ? 29 : 28
    return constValue.solarMonth[m - 1]!
  }

  /**
   * 获得当前月份第一天是星期几
   * @param {number} y 年
   * @param {number} m 月
   * @returns {number} 返回星期数字[0-6]
   */
  solarWeeks(y: number, m: number) {
    return this.solarWeek(y, m, 1)
  }

  /**
   * 获取公历某一天是星期几
   * @param {number} y 年
   * @param {number} m 月
   * @param {number} d 日
   * @returns {number} 返回星期数字[0-6]
   */
  solarWeek(y: number, m: number, d: number) {
    const date = new Date(y, m - 1, d)
    const week = date.getDay()
    return week
  }

  /**
   * 返回农历月份通俗表示法
   * @param {number} m 农历月
   * @returns {string} 返回农历月份通俗表示法：'正月'
   */
  toChinaMonth(m: number) {
    const r = String(m).slice(0, 1) == '0'
    return r
      ? `\u95F0${constValue.nStr3[m - 1]}\u6708`
      : `${constValue.nStr3[m - 1]}\u6708` // 加上"月"字
  }

  /**
   * 返回农历日期通俗表示法
   * @param {number} d 农历日
   * @returns {string} 返回农历日期通俗表示法：‘初一’
   */
  toChinaDay(d: number) {
    const str
      = d == 10 ? constValue.nStr2[0]! : constValue.nStr2[Math.floor(d / 10)]!
    return str + (d % 10 ? constValue.nStr1[d % 10] : constValue.nStr1[10])
  }

  /**
   * 农历年份转生肖
   * @param {number} y 农历年
   * @returns {string} 农历年份转生肖
   */
  getAnimal(y: number) {
    return constValue.Animals[(y - 4) % 12]!
  }

  /**
   * 返回公历日期所属星座
   * @param {number} m 月
   * @param {number} d 日
   * @returns {string} 返回星座信息
   */
  toAstro(m: number, d: number) {
    const s
      = '\u9B54\u7FAF\u6C34\u74F6\u53CC\u9C7C\u767D\u7F8A\u91D1\u725B\u53CC\u5B50\u5DE8\u87F9\u72EE\u5B50\u5904\u5973\u5929\u79E4\u5929\u874E\u5C04\u624B\u9B54\u7FAF'
    const arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
    const i = m * 2 - (d < arr[m - 1]! ? 2 : 0)
    return `${s.slice(i, i + 2)}\u5EA7`
  }

  /**
   * 根据公历日期返回农历日期
   * @param {number} y 年
   * @param {number} m 月
   * @param {number} d 日
   * @returns {string} 返回农历日期,如果是闰月则月份前含0
   */
  getLunars(y: number, m: number, d: number) {
    let i
    let leap = 0
    let temp = 0
    let offset = (Date.UTC(y, m - 1, d) - Date.UTC(1900, 0, 31)) / 86400000
    for (i = 1900; i < 2101 && offset > 0; i++) {
      temp = this.lYearDays(i)
      offset -= temp
    }
    if (offset < 0) {
      offset += temp
      i--
    }
    // 获取闰月
    const year = i
    leap = this.leapMonth(i)
    let isLeap = false
    // 校验闰月
    for (i = 1; i < 13 && offset > 0; i++) {
      if (leap > 0 && i == leap + 1 && !isLeap) {
        --i
        isLeap = true
        temp = this.leapDays(year) // 闰月天数
      }
      else {
        temp = this.monthDays(year, i) // 普通月天数
      }
      if (isLeap && i == leap + 1)
        isLeap = false
      offset -= temp
    }
    if (offset == 0 && leap > 0 && i == leap + 1) {
      if (isLeap) {
        isLeap = false
      }
      else {
        isLeap = true
        --i
      }
    }
    if (offset < 0) {
      offset += temp
      --i
    }
    // 农历月
    const month = isLeap ? `0${i}` : i
    // 农历日
    const day = ++offset
    return `${year}-${month}-${day}`
  }

  /**
   * 返回农历年闰月，没有闰月则返回0
   * @param {number} y 农历年
   * @returns {number} 农历年闰月月份数字，没有闰月则返回0
   */
  leapMonth(y: number) {
    return constValue.lunarInfo[y - 1900]! & 0xF
  }

  /**
   * 返回农历年闰月的天数，没有闰月则返回0
   * @param {number} y 农历年
   * @returns {number} 闰月的天数，没有闰月则返回0
   */
  leapDays(y: number) {
    return this.leapMonth(y)
      ? constValue.lunarInfo[y - 1900]! & 0x10000
        ? 30
        : 29
      : 0
  }

  /**
   * 查询公历日期节日
   * @param {number} m 月
   * @param {number} d 日
   * @returns {string | boolean} 返回节日信息，不是节日则返回false
   */
  getSolarDay(m: number, d: number) {
    let solarDay: false | string = false
    for (let i = 0; i < constValue.sFtv.length; i++) {
      if (
        Number.parseInt(constValue.sFtv[i]!.slice(0, 2)) == m
        && Number.parseInt(constValue.sFtv[i]!.slice(2, 4)) == d
      ) {
        solarDay = constValue.sFtv[i]!.slice(5)
      }
    }
    return solarDay
  }

  /**
   * 通过农历日期获取农历节日
   * @param {number} y 农历年
   * @param {number|string} m 农历月，如果是闰月则为字符串‘07’
   * @param {number} d 农历日
   * @returns {string|false} 返回农历节日，没有节日则返回false
   */
  getlunarDay(y: number, m: number, d: number) {
    if (String(m).slice(0, 1) == '0')
      return false // 如果是闰月则没有节日
    let lunarDay: false | string = false
    for (let i = 0; i < constValue.lFtv.length; i++) {
      if (
        Number.parseInt(constValue.lFtv[i]!.slice(0, 2)) == m
        && Number.parseInt(constValue.lFtv[i]!.slice(2, 4)) == d
      ) {
        lunarDay = constValue.lFtv[i]!.slice(5)
      }
    }
    // 判断是否为除夕
    if (m == 12 && this.monthDays(y, m) == d)
      lunarDay = '除夕'
    return lunarDay
  }

  /**
   * 返回农历一年的天数
   * @param {number} y 农历年份
   * @returns {number} 一年的天数
   */
  lYearDays(y: number) {
    let i
    let sum = 348
    for (i = 0x8000; i > 0x8; i >>= 1) {
      sum += constValue.lunarInfo[y - 1900]! & i ? 1 : 0
    }
    return sum + this.leapDays(y)
  }

  /**
   * 获取农历非闰月的总天数
   * @param {number} y 农历年
   * @param {number} m 农历月
   * @returns {number} 返回农历非闰月的天数
   */
  monthDays(y: number, m: number) {
    return constValue.lunarInfo[y - 1900]! & (0x10000 >> m) ? 30 : 29
  }

  /**
   * 获取公历年第n个节气日期
   * @param {number} y 年
   * @param {number} n 第几个节气
   * @returns {string} 返回日期,0506
   */
  getTerm(y: number, n: number) {
    // if (y < 1900 || y > 2100 || n < 1 || n > 24) {
    //   return -1;
    // }
    // let _table = constValue.sTermInfo[y - 1900]!;
    // const _calcDay = [];
    // for (let index = 0; index < _table.length; index += 5) {
    //   const chunk = parseInt('0x' + _table.slice(index, 5)).toString();
    //   _calcDay.push(chunk[0], chunk.slice(1, 2), chunk[3], chunk.slice(4, 2));
    // }
    // console.log(1231231321, _calcDay[n - 1]!);

    // return Number(_calcDay[n - 1]!);
    const _table = constValue.sTermInfo[y - 1900]!
    const _info = [
      Number.parseInt(`0x${_table.slice(0, 5)}`).toString(),
      Number.parseInt(`0x${_table.slice(5, 10)}`).toString(),
      Number.parseInt(`0x${_table.slice(10, 15)}`).toString(),
      Number.parseInt(`0x${_table.slice(15, 20)}`).toString(),
      Number.parseInt(`0x${_table.slice(20, 25)}`).toString(),
      Number.parseInt(`0x${_table.slice(25)}`).toString(),
    ] as const
    const d = [
      _info[0].slice(0, 1),
      _info[0].slice(1, 3),
      _info[0].slice(3, 4),
      _info[0].slice(4, 6),

      _info[1].slice(0, 1),
      _info[1].slice(1, 3),
      _info[1].slice(3, 4),
      _info[1].slice(4, 6),

      _info[2].slice(0, 1),
      _info[2].slice(1, 3),
      _info[2].slice(3, 4),
      _info[2].slice(4, 6),

      _info[3].slice(0, 1),
      _info[3].slice(1, 3),
      _info[3].slice(3, 4),
      _info[3].slice(4, 6),

      _info[4].slice(0, 1),
      _info[4].slice(1, 3),
      _info[4].slice(3, 4),
      _info[4].slice(4, 6),

      _info[5].slice(0, 1),
      _info[5].slice(1, 3),
      _info[5].slice(3, 4),
      _info[5].slice(4, 6),
    ]
    return d[n - 1]
  }
}

export default new DateClass()
